package com.crm.business.crm.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.crm.business.admin.service.AdminService;
import com.crm.business.admin.service.IAdminDeptService;
import com.crm.business.admin.service.IAdminUserManageDeptService;
import com.crm.business.admin.service.IAdminUserService;
import com.crm.business.crm.mapper.CrmRoiStatisMapper;
import com.crm.business.crm.service.*;
import com.crm.business.servlet.BaseServiceImpl;
import com.crm.business.utils.UserUtil;
import com.crm.common.admin.entity.BO.AdminUserBO;
import com.crm.common.admin.entity.PO.AdminDept;
import com.crm.common.admin.entity.PO.AdminUserManageDept;
import com.crm.common.admin.entity.VO.AdminUserVO;
import com.crm.common.crm.constant.*;
import com.crm.common.crm.entity.BO.CrmRoiPutinPageBO;
import com.crm.common.crm.entity.PO.*;
import com.crm.common.crm.entity.VO.*;
import com.crm.common.ka.core.common.Const;
import com.crm.common.ka.core.entity.BasePage;
import com.crm.common.ka.core.feign.admin.entity.AdminUserEntityVO;
import com.crm.common.utils.DateUtils;
import com.crm.common.utils.StringUtils;
import com.crm.common.utils.spring.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;


/**
 * <p>
 * 投放消耗表 服务实现类
 * </p>
 *
 * @author zhangzhiwei
 * @since 2020-05-21
 */
@Service
@Slf4j
public class CrmRoiStatisServiceImpl extends BaseServiceImpl<CrmRoiStatisMapper, CrmRoiStatis> implements ICrmRoiStatisService, CrmPageService {

    @Autowired
    private ICrmRoiPutinService crmRoiPutinService;

    @Qualifier("roiStatisExecutor")
    @Autowired
    private Executor roiStatisExecutor;

    @Qualifier("roiDetailStatisExecutor")
    @Autowired
    private Executor roiDetailStatisExecutor;

    @Autowired
    private ICrmReceivablesService crmReceivablesService;

    @Autowired
    private ICrmLeadsService crmLeadsService;

    @Autowired
    private AdminService adminService;

    @Autowired
    private ICrmReFundService crmReFundService;

    @Autowired
    private ICrmPutinMoneyService crmPutinMoneyService;

    @Autowired
    private IAdminUserService adminUserService;


    @Override
    public String[] appendSearch() {
        return new String[0];
    }

    @Override
    public void setOtherField(Map<String, Object> map) {

    }

    @Override
    public CrmEnum getLabel() {
        return null;
    }

    @Override
    public List<CrmModelFiledVO> queryDefaultField() {
        return null;
    }

    /**
     * 查询ROI统计
     * @param crmRoiPutinPageBO
     * @return
     */
    @Override
    public BasePage<CrmRoiStatis> queryAllRoiStatis(CrmRoiPutinPageBO crmRoiPutinPageBO){
        return baseMapper.queryAllRoiStatis(crmRoiPutinPageBO.parse(), crmRoiPutinPageBO);
    }

    /**
     * ROI统计明细列表
     * @param crmRoiPutinPageBO
     * @return
     */
    @Override
    public BasePage<CrmRoiStatisVO> queryPutinStatisForSource(CrmRoiPutinPageBO crmRoiPutinPageBO){

        // 获取选择部门及下属部门的所有用户
        List<Long> userList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(crmRoiPutinPageBO.getDeptIds())){
            long[] longs = crmRoiPutinPageBO.getDeptIds().stream().mapToLong(t -> t.longValue()).toArray();
            userList.addAll(adminService.queryUserListByDeptIds(longs));

            List<Long> authUserIdList = new ArrayList<>();
            authUserIdList.addAll(SpringUtils.getBean(AdminService.class).queryUserIdsByRoleIds());
            //管理部门 数据权限
            List<Long> ManageDeptUserIdList = SpringUtils.getBean(AdminService.class).queryUserIdsByManageDept();
            authUserIdList.addAll(ManageDeptUserIdList);
            authUserIdList = authUserIdList.stream().distinct().collect(Collectors.toList());
            userList.retainAll(authUserIdList);
            crmRoiPutinPageBO.setUserIdList(userList);

        }else{
            userList.addAll(SpringUtils.getBean(AdminService.class).queryUserIdsByRoleIds());
            //管理部门 数据权限
            List<Long> ManageDeptUserIdList = SpringUtils.getBean(AdminService.class).queryUserIdsByManageDept();
            userList.addAll(ManageDeptUserIdList);
            userList = userList.stream().distinct().collect(Collectors.toList());
            crmRoiPutinPageBO.setUserIdList(userList);
        }

        // 获取部门及管理部门
        List<AdminDept> manageDeptList = SpringUtils.getBean(IAdminUserManageDeptService.class).queryManageDeptListByUserId(UserUtil.getUserId());
        List<Integer> manageDeptIdList = manageDeptList.stream().map(AdminDept::getDeptId).collect(Collectors.toList());
        List<Integer> allDeptIds = new ArrayList<>();
        for(Integer deptId : manageDeptIdList){
            allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(deptId));
            allDeptIds.add(deptId);
        }
        allDeptIds.add(UserUtil.getUser().getDeptId());
        allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(UserUtil.getUser().getDeptId()));
        allDeptIds = allDeptIds.stream().distinct().collect(Collectors.toList());

        if(!CollectionUtils.isEmpty(crmRoiPutinPageBO.getDeptIds())){
            allDeptIds.retainAll(crmRoiPutinPageBO.getDeptIds());
        }

        crmRoiPutinPageBO.setDeptIds(allDeptIds);

        if(CollectionUtils.isEmpty(allDeptIds)){
            BasePage<CrmRoiStatisVO> crmRoiStatisVOS = new BasePage<>();
            Map<String, Object> dataMap = new HashMap<>();
            dataMap.put("averageRoi",0.00);
            // 实际ROI
            dataMap.put("realityRoi",0.00);
            // 预期ROI
            dataMap.put("expectRoi",0.00);
            crmRoiStatisVOS.setExtraData(dataMap);
            return crmRoiStatisVOS;
        }

        // 默认展示上个月
        if(ObjectUtil.isEmpty(crmRoiPutinPageBO.getStartPutinFormDate()) && ObjectUtil.isEmpty(crmRoiPutinPageBO.getEndPutinFormDate())){
            LocalDate today = LocalDate.now();
            LocalDate monthAgo = today.minusMonths(1);
            crmRoiPutinPageBO.setMonth(DateUtils.parseDateToStr(DateUtils.YYYY_MM,DateUtils.toDate(monthAgo)));
        }

        BasePage<CrmRoiStatisVO> crmRoiStatisVOS = baseMapper.queryPutinStatisForSource(crmRoiPutinPageBO.parse(), crmRoiPutinPageBO);
        List<CrmRoiStatisVO> crmRoiStatisList = baseMapper.queryAllPutinStatisForSource(crmRoiPutinPageBO);

        // 计算ROI
        final BigDecimal[] allPutinMoney = {new BigDecimal(0.00)}; // 总消耗
        final Integer[] allLeadsNum = {0}; // 线索量
        final BigDecimal[] allReceivablesMoney = {new BigDecimal(0.00)}; // 总回款
        final BigDecimal[] allExpectReceivablesMoney = {new BigDecimal(0.00)}; // 总预期回款
        final BigDecimal[] allRefundMoney = {new BigDecimal(0.00)}; // 退款金额
        final BigDecimal[] realityRoi = {new BigDecimal(0.00)};// 实际ROI(每天ROI总和/天数)
        final BigDecimal[] expectRoi = {new BigDecimal(0.00)};// 预期ROI
        int dayNum = 0;

        Map<String, Date> stringDateMap = baseMapper.queryMaxAndMinDate(crmRoiPutinPageBO);
        if(!CollectionUtils.isEmpty(stringDateMap)){
            dayNum = DateUtils.differentDaysByMillisecond(stringDateMap.get("maxDate"),stringDateMap.get("minDate"));
        }

        final List<Long> finalUserList = new ArrayList<>();
        finalUserList.addAll(userList);

        //20231103 异步 roiDetailStatisExecutor
        CompletableFuture<Void> pageDataFuture = CompletableFuture.runAsync(() -> {

            crmRoiStatisVOS.getList().forEach(item -> {
                // 消耗部门名称回显
                if(ObjectUtil.isNotEmpty(item.getDeptId())){
                    String deptName = adminService.queryAllDeptNameByDeptId(item.getDeptId());
                    if(StringUtils.isNotBlank(deptName)){
                        deptName = deptName.replace("|","-");
                    }
                    item.setDeptName(deptName);
                }

                crmRoiPutinPageBO.setUserIdList(finalUserList);

                List<Integer> deptIdList = new ArrayList<>();
                deptIdList.add(item.getDeptId());
                deptIdList.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(item.getDeptId()));
                long[] deptIds = deptIdList.stream().mapToLong(Long::valueOf).toArray();
                List<Long> deptUserIds = adminService.queryUserListByDeptIds(deptIds);
                deptUserIds.retainAll(finalUserList);
                crmRoiPutinPageBO.setUserIdList(deptUserIds);
                crmRoiPutinPageBO.setPutinPlatform(item.getPutinPlatform());
                crmRoiPutinPageBO.setStartPutinFormDate(DateUtils.parseDate(item.getPutinFormDate()));
                crmRoiPutinPageBO.setEndPutinFormDate(DateUtils.parseDate(item.getPutinFormDate()));

                if(!CollectionUtils.isEmpty(crmRoiPutinPageBO.getUserIdList())){
                    Integer leadsCount = crmLeadsService.queryLeadsStatisForSource(crmRoiPutinPageBO);
                    item.setLeadsCount(leadsCount);

                    // 回款金额(负责人所在部门)
                    BigDecimal receivablesMoney = crmReceivablesService.queryReceivablesMoneyByData(crmRoiPutinPageBO);
                    item.setReceivablesMoney(receivablesMoney);

                    BigDecimal expectReceivablesMoney = crmReceivablesService.queryExpectReceivablesMoneyByData(crmRoiPutinPageBO);
                    item.setExpectReceivablesMoney(expectReceivablesMoney);

                    // 退款金额(负责人所在部门)
                    BigDecimal refundMoney = crmReFundService.queryRefundMoneyByData(crmRoiPutinPageBO);
                    item.setRefundMoney(refundMoney);
                }else{
                    item.setLeadsCount(0);
                    item.setReceivablesMoney(new BigDecimal("0.00"));
                    item.setExpectReceivablesMoney(new BigDecimal("0.00"));
                    item.setRefundMoney(new BigDecimal("0.00"));
                }
            });

        }, roiDetailStatisExecutor);

        CompletableFuture<Void> allDataFuture = CompletableFuture.runAsync(() -> {
            crmRoiStatisList.forEach(item -> {

                crmRoiPutinPageBO.setUserIdList(finalUserList);
                List<Integer> deptIdList = new ArrayList<>();
                deptIdList.add(item.getDeptId());
                deptIdList.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(item.getDeptId()));
                long[] deptIds = deptIdList.stream().mapToLong(Long::valueOf).toArray();
                List<Long> deptUserIds = adminService.queryUserListByDeptIds(deptIds);
                deptUserIds.retainAll(finalUserList);
                crmRoiPutinPageBO.setUserIdList(deptUserIds);

                crmRoiPutinPageBO.setPutinPlatform(item.getPutinPlatform());
                crmRoiPutinPageBO.setStartPutinFormDate(DateUtils.parseDate(item.getPutinFormDate()));
                crmRoiPutinPageBO.setEndPutinFormDate(DateUtils.parseDate(item.getPutinFormDate()));

                // 总消耗
                allPutinMoney[0] = allPutinMoney[0].add(item.getPutinMoney());

                if(!CollectionUtils.isEmpty(crmRoiPutinPageBO.getUserIdList())){
                    // 线索量
                    Integer leadsNum = crmLeadsService.queryLeadsStatisForSource(crmRoiPutinPageBO);
                    allLeadsNum[0] = allLeadsNum[0] + leadsNum;
                    // 回款金额(负责人所在部门)
                    BigDecimal receivablesMoney = crmReceivablesService.queryReceivablesMoneyByData(crmRoiPutinPageBO);
                    allReceivablesMoney[0] = allReceivablesMoney[0].add(receivablesMoney);
                    // 预期回款金额
                    BigDecimal expectReceivablesMoney = crmReceivablesService.queryExpectReceivablesMoneyByData(crmRoiPutinPageBO);
                    allExpectReceivablesMoney[0] = allExpectReceivablesMoney[0].add(expectReceivablesMoney);
                    // 退款金额
                    BigDecimal refundMoney = crmReFundService.queryRefundMoneyByData(crmRoiPutinPageBO);
                    allRefundMoney[0] = allRefundMoney[0].add(refundMoney);

                    //实际ROI
                    if(item.getPutinMoney().compareTo(new BigDecimal(0.00)) > 0){
                        BigDecimal dayRoi = receivablesMoney.divide(item.getPutinMoney(), 2, RoundingMode.HALF_UP);
                        realityRoi[0] = realityRoi[0].add(dayRoi);
                        log.info("item.getPutinMoney:{},item.getReceivablesMoney,{},dayRoi:{}",item.getPutinMoney(),receivablesMoney,dayRoi);
                    }
                    // 预期ROI
                    if(item.getPutinMoney().compareTo(new BigDecimal(0.00)) > 0){
                        BigDecimal expectDayRoi = expectReceivablesMoney.divide(item.getPutinMoney(),2,RoundingMode.HALF_UP);
                        expectRoi[0] = expectRoi[0].add(expectDayRoi);
                        log.info("item.getPutinMoney:{},expectReceivablesMoney:{},expectDayRoi:{}",item.getPutinMoney(),expectReceivablesMoney,expectDayRoi);
                    }
                }
            });
        }, roiDetailStatisExecutor);

        CompletableFuture.allOf(pageDataFuture,allDataFuture).exceptionally((e) -> {
            e.printStackTrace();
            return null;
        }).join();

        // 平均ROI
        Map<String, Object> dataMap = new HashMap<>();
        if(allPutinMoney[0].compareTo(new BigDecimal(0.00)) > 0){
            dataMap.put("averageRoi",allReceivablesMoney[0].divide(allPutinMoney[0],2,RoundingMode.HALF_UP));
        }else{
            dataMap.put("averageRoi",0.00);
        }
        // 实际ROI
        if(dayNum != 0){
            dataMap.put("realityRoi",realityRoi[0].divide(new BigDecimal(dayNum),2,RoundingMode.HALF_UP));
        }else{
            dataMap.put("realityRoi",0.00);
        }
        // 预期ROI
        if(allPutinMoney[0].compareTo(new BigDecimal(0.00)) > 0){
            dataMap.put("expectRoi",allExpectReceivablesMoney[0].divide(allPutinMoney[0],2,RoundingMode.HALF_UP));
        }else{
            dataMap.put("expectRoi",0.00);
        }
        dataMap.put("allLeadsNum",allLeadsNum[0]);
        dataMap.put("allPutinMoney",allPutinMoney[0]);
        dataMap.put("allReceivablesMoney",allReceivablesMoney[0]);
        dataMap.put("allExpectReceivablesMoney",allExpectReceivablesMoney[0]);
        dataMap.put("allRefundMoney",allRefundMoney[0]);
        crmRoiStatisVOS.setExtraData(dataMap);
        return crmRoiStatisVOS;
    }


    @Override
    public void statisRoi(){
        roiStatisExecutor.execute(() -> {
            SpringUtils.getBean(ICrmRoiStatisService.class).statisRoiJob();
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void statisRoiJob(){
        baseMapper.deleteAllPutinStatis();

        List<String> sourceList = crmPutinMoneyService.querySource();

        List<Map<String, Object>> allPutinStatis = crmRoiPutinService.selectAllPutinStatis();
        List<Map<String, Object>> allReceivablesMoneyStatis = crmReceivablesService.queryPutinStatis(null,null);
        Map<String, CrmRoiStatis> statisMap = new HashMap<>();

        if(allPutinStatis == null || allPutinStatis.size() <= 0){
            return;
        }

        for(String source : sourceList){
            CrmRoiStatis crmRoiStatis = new CrmRoiStatis();
            crmRoiStatis.setPutinPlatform(source);
            crmRoiStatis.setAllPutinMoney(new BigDecimal(0));
            crmRoiStatis.setReceivablesMoney(new BigDecimal(0));
            crmRoiStatis.setAllLeadsNum(0);
            crmRoiStatis.setAllLeadsNum(0);
            statisMap.put(source,crmRoiStatis);
        }

        for(Map<String,Object> map : allPutinStatis){
            String source = String.valueOf(map.get("putinPlatform"));
            CrmRoiStatis crmRoiStatis = statisMap.get(source);
            if(crmRoiStatis != null){
                crmRoiStatis.setAllPutinMoney(new BigDecimal(String.valueOf(map.get("allPutinMoney"))));
                statisMap.put(source,crmRoiStatis);
            }else{
                crmRoiStatis = new CrmRoiStatis();
                statisMap.put(source,crmRoiStatis);
            }
        }

        // 平均ROI(总消耗/总回款金额)
        for (Map<String,Object> map : allReceivablesMoneyStatis){
            String source = String.valueOf(map.get("source"));
            CrmRoiStatis crmRoiStatis = statisMap.get(source);
            if(crmRoiStatis != null){
                crmRoiStatis.setReceivablesMoney(new BigDecimal(String.valueOf(map.get("money"))));
                BigDecimal allPutinMoney = crmRoiStatis.getAllPutinMoney();
                BigDecimal receivablesMoney = crmRoiStatis.getReceivablesMoney();
                if(allPutinMoney.compareTo(new BigDecimal(0.00)) <= 0){
                    crmRoiStatis.setAverageRoi(new BigDecimal(0));
                }else {
                    BigDecimal avgRoi = receivablesMoney.divide(allPutinMoney,2, RoundingMode.HALF_UP);
                    crmRoiStatis.setAverageRoi(avgRoi);
                }
            }else{
                crmRoiStatis = new CrmRoiStatis();
            }
            statisMap.put(crmRoiStatis.getPutinPlatform(),crmRoiStatis);
        }

        // 实际ROI(每日ROI总和/天数)(近3个月)(20231018-近一年)
        LocalDate today = LocalDate.now();
        LocalDate yearsAgo = today.minus(1, ChronoUnit.YEARS);
        yearsAgo = yearsAgo.minus(1, ChronoUnit.DAYS);
        Date threeMonthsAgoDate = DateUtils.toDate(yearsAgo);

        LocalDate yesterday = LocalDate.now();
        LocalDate yesterdayAgo = yesterday.minus(1, ChronoUnit.DAYS);
        Date yesterdayAgoDate = DateUtils.toDate(yesterdayAgo);

        // 天数
        int dayNum = DateUtils.differentDaysByMillisecond(yesterdayAgoDate, threeMonthsAgoDate) + 1;

        // 近3个月ROI总和(20231018-近一年ROI总和)
        final BigDecimal[] roiMonthSum = {new BigDecimal(0.00)};

        // 实际ROI
        List<CrmRoiStatisVO> sourceStatisList = crmReceivablesService.queryRoiStatis(DateUtils.dateTime(threeMonthsAgoDate), DateUtils.dateTime(yesterdayAgoDate));
        Map<String, List<CrmRoiStatisVO>> crmRoiStatisVOMap = sourceStatisList.stream().collect(Collectors.groupingBy(CrmRoiStatisVO::getPutinPlatform));
        crmRoiStatisVOMap.keySet().forEach(item -> {
            List<CrmRoiStatisVO> crmRoiStatisVOS = crmRoiStatisVOMap.get(item);
            if(!CollectionUtils.isEmpty(crmRoiStatisVOS)){
                for(CrmRoiStatisVO roiStatisVO : crmRoiStatisVOS){
                    BigDecimal putinMoney = crmRoiPutinService.querySumMoney(item, roiStatisVO.getLeadsFormTime(), roiStatisVO.getLeadsFormTime());

                    String money = String.valueOf(roiStatisVO.getReceivablesMoney());
                    if(putinMoney.compareTo(new BigDecimal(0)) > 0){
                        BigDecimal dayRoi = new BigDecimal(money).divide(putinMoney, 2, RoundingMode.HALF_UP);
                        if(dayRoi.compareTo(new BigDecimal(0.00)) > 0){
                            log.info("source:{},dayRoi:{}",item, dayRoi);
                        }
                        roiMonthSum[0] = roiMonthSum[0].add(dayRoi);
                    }
                }
                CrmRoiStatis crmRoiStatis = statisMap.get(item);
                if(crmRoiStatis != null){
                    BigDecimal roiMonth = roiMonthSum[0].divide(new BigDecimal(dayNum), 2, RoundingMode.HALF_UP);
                    crmRoiStatis.setRoiMonth(roiMonthSum[0]);
                    crmRoiStatis.setRealityRoi(roiMonth);
                }else{
                    crmRoiStatis = new CrmRoiStatis();
                }
                statisMap.put(item, crmRoiStatis);
                roiMonthSum[0] = new BigDecimal(0.00);
            }else{
                CrmRoiStatis crmRoiStatis = statisMap.get(item);
                if(crmRoiStatis != null){
                    crmRoiStatis.setRoiMonth(roiMonthSum[0]);
                    crmRoiStatis.setRealityRoi(new BigDecimal(0.00));
                }else{
                    crmRoiStatis = new CrmRoiStatis();
                }
                statisMap.put(item, crmRoiStatis);
                roiMonthSum[0] = new BigDecimal(0.00);
            }
        });

        // 预期ROI
        CrmRoiPutinPageBO pageBO = new CrmRoiPutinPageBO();
        pageBO.setStartPutinFormDate(threeMonthsAgoDate);
        pageBO.setEndPutinFormDate(yesterdayAgoDate);

        for(Map<String,Object> map : allPutinStatis){
            String source = String.valueOf(map.get("putinPlatform"));
            CrmRoiStatis crmRoiStatis = statisMap.get(source);
            if(crmRoiStatis != null){
                pageBO.setPutinPlatform(source);
                BigDecimal expectReceivablesMoney = crmReceivablesService.queryExpectReceivablesMoneyByData(pageBO);
                BigDecimal putinMoney = crmRoiPutinService.querySumMoney(source, DateUtils.dateTime(threeMonthsAgoDate), DateUtils.dateTime(yesterdayAgoDate));

                if(putinMoney != null && putinMoney.compareTo(new BigDecimal(0.00)) > 0){
                    BigDecimal expectRoi = expectReceivablesMoney.divide(putinMoney, 2, RoundingMode.HALF_UP);
                    crmRoiStatis.setExpectRoi(expectRoi);
                    statisMap.put(source,crmRoiStatis);
                }
            }else{
                crmRoiStatis = new CrmRoiStatis();
                statisMap.put(source,crmRoiStatis);
            }
        }

        //平均客单价(总消耗/总表单数)
        List<Map<String, Long>> allLeadsStatis = crmLeadsService.queryAllLeadsStatis(null,null);
        for(Map<String,Long> map : allLeadsStatis){
            String source = String.valueOf(map.get("source"));
            CrmRoiStatis crmRoiStatis = statisMap.get(source);
            if(crmRoiStatis != null){
                // 总消耗
                BigDecimal allPutinMoney = crmRoiStatis.getAllPutinMoney();
                if(allPutinMoney != null){
                    // 表单数
                    Long leadsCount = map.get("leadsCount");
                    if(leadsCount != null){
                        crmRoiStatis.setAllLeadsNum(Integer.parseInt(String.valueOf(leadsCount)));
                        BigDecimal averagePrice = allPutinMoney.divide(new BigDecimal(leadsCount), 2, RoundingMode.HALF_UP);
                        crmRoiStatis.setAveragePrice(averagePrice);
                        statisMap.put(source, crmRoiStatis);
                    }
                }

            }
        }

        // 实际客单价(昨日消耗/昨日表单量)
        List<CrmRoiStatisVO> putinStatisForData = crmRoiPutinService.queryPutinStatisForData(DateUtils.dateTime(yesterdayAgoDate), DateUtils.dateTime(yesterdayAgoDate));
        Map<String, BigDecimal> putinStatis = putinStatisForData.stream().collect(Collectors.toMap(CrmRoiStatisVO::getPutinPlatform, CrmRoiStatisVO::getPutinMoney));
        List<Map<String, Long>> leadsStatis = crmLeadsService.queryAllLeadsStatis(DateUtils.dateTime(yesterdayAgoDate),DateUtils.dateTime(yesterdayAgoDate));
        for(Map<String,Long> map : leadsStatis){
            String source = String.valueOf(map.get("source"));
            CrmRoiStatis crmRoiStatis = statisMap.get(source);
            if(crmRoiStatis != null){
                // 昨日消耗
                BigDecimal putinMoney = putinStatis.get(source);;
                if(putinMoney == null){
                    crmRoiStatis.setRealityPrice(new BigDecimal(0));
                    statisMap.put(source, crmRoiStatis);
                }else{
                    // 昨日表单数
                    Long leadsCount = map.get("leadsCount");
                    if(leadsCount == null || leadsCount == 0){
                        crmRoiStatis.setRealityPrice(new BigDecimal(0));
                        statisMap.put(source, crmRoiStatis);
                    }else{
                        BigDecimal averagePrice = putinMoney.divide(new BigDecimal(leadsCount), 2, RoundingMode.HALF_UP);
                        crmRoiStatis.setRealityPrice(averagePrice);
                        statisMap.put(source, crmRoiStatis);
                    }
                }
            }
        }

        statisMap.keySet().forEach(item -> {
            CrmRoiStatis crmRoiStatis = statisMap.get(item);
            if(crmRoiStatis != null){
                if(StringUtils.isNotBlank(crmRoiStatis.getPutinPlatform())){
                    save(crmRoiStatis);
                }
            }
        });

        log.info("roiStatis.lastResult=>" + JSONObject.toJSONString(statisMap));

    }

    /**
     * ROI月度统计
     * @param crmRoiPutinPageBO
     */
    @Override
    public Map<String, Object> roiStatisForMonth(CrmRoiPutinPageBO crmRoiPutinPageBO){

        List<AdminDept> manageDeptList = SpringUtils.getBean(IAdminUserManageDeptService.class).queryManageDeptListByUserId(UserUtil.getUserId());
        List<Integer> manageDeptIdList = manageDeptList.stream().map(AdminDept::getDeptId).collect(Collectors.toList());
        List<Integer> allDeptIds = new ArrayList<>();
        for(Integer deptId : manageDeptIdList){
            allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(deptId));
            allDeptIds.add(deptId);
        }
        allDeptIds.add(UserUtil.getUser().getDeptId());
        allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(UserUtil.getUser().getDeptId()));
        allDeptIds = allDeptIds.stream().distinct().collect(Collectors.toList());

        crmRoiPutinPageBO.setDeptIds(allDeptIds);

        // 获取选择部门及下属部门的所有用户
        List<Long> userList = new ArrayList<>();
        if(crmRoiPutinPageBO.getDeptIds() != null){
            long[] longs = crmRoiPutinPageBO.getDeptIds().stream().mapToLong(t -> t.longValue()).toArray();
            userList.addAll(adminService.queryUserListByDeptIds(longs));

            List<Long> authUserIdList = new ArrayList<>();
            authUserIdList.addAll(SpringUtils.getBean(AdminService.class).queryUserIdsByRoleIds());
            //管理部门 数据权限
            List<Long> ManageDeptUserIdList = SpringUtils.getBean(AdminService.class).queryUserIdsByManageDept();
            authUserIdList.addAll(ManageDeptUserIdList);
            authUserIdList = authUserIdList.stream().distinct().collect(Collectors.toList());
            userList.retainAll(authUserIdList);
            crmRoiPutinPageBO.setUserIdList(userList);

        }else{
            userList.addAll(SpringUtils.getBean(AdminService.class).queryUserIdsByRoleIds());
            //管理部门 数据权限
            List<Long> ManageDeptUserIdList = SpringUtils.getBean(AdminService.class).queryUserIdsByManageDept();
            userList.addAll(ManageDeptUserIdList);
            userList = userList.stream().distinct().collect(Collectors.toList());
            crmRoiPutinPageBO.setUserIdList(userList);
        }

        // 平均ROI(总消耗/总回款)
        String month = crmRoiPutinPageBO.getMonth();
        if(StringUtils.isBlank(month)){
            LocalDate today = LocalDate.now();
            LocalDate monthAgo = today.minusMonths(1);
            month = DateUtils.parseDateToStr(DateUtils.YYYY_MM,DateUtils.toDate(monthAgo));
            crmRoiPutinPageBO.setMonth(month);
        }

        String[] split = month.split("-");
        LocalDate startDate = LocalDate.of(Integer.parseInt(split[0]), Integer.parseInt(split[1]), 1);
        LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());

        // 总消耗
        List<CrmRoiStatisVO> putinStatisByFormDate = crmRoiPutinService.queryPutinStatisByFormDate(crmRoiPutinPageBO);
        Map<String, BigDecimal> putinStatis = putinStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getPutinFormDate, CrmRoiStatisVO::getPutinMoney));

        // 总回款
        List<CrmRoiStatisVO> receivablesStatisByFormDate = crmReceivablesService.queryPutinStatisByFormDate(crmRoiPutinPageBO);
        Map<String, BigDecimal> receivablesStatis = receivablesStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getLeadsFormTime, CrmRoiStatisVO::getReceivablesMoney));
        // 预期收益
        List<CrmRoiStatisVO> expectReceivablesStatisByFormDate = crmReceivablesService.queryExpectPutinStatisByFormDate(crmRoiPutinPageBO);
        Map<String, BigDecimal> expectReceivablesStatis = expectReceivablesStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getLeadsFormTime, CrmRoiStatisVO::getExpectReceivablesMoney));

        List<String> dayList = new ArrayList<>();
        List<BigDecimal> dayRoiList = new ArrayList<>();
        List<BigDecimal> expectDayRoiList = new ArrayList<>();
        List<Map<String,Object>> roiTableList = new ArrayList<>();

        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            String currentDateToStr = String.valueOf(currentDate);
            String day = DateFormatUtils.format(DateUtils.toDate(currentDate), "MM-dd");
            dayList.add(day);
            BigDecimal putinMoney = putinStatis.get(currentDateToStr);

            Map<String, Object> roiTable = new HashMap<>();
            roiTable.put("day",day);

            if(putinMoney == null){
                dayRoiList.add(new BigDecimal(0.00));
                expectDayRoiList.add(new BigDecimal(0.00));

                roiTable.put("dayRoi",new BigDecimal("0.00"));
                roiTable.put("expectDayRoi",new BigDecimal("0.00"));
                roiTableList.add(roiTable);

                currentDate = currentDate.plusDays(1);  // 将日期增加1天
                continue;
            }

            // 平均ROI
            BigDecimal receivablesMoney = receivablesStatis.get(currentDateToStr + " 00:00:00");
            if(putinMoney.compareTo(new BigDecimal(0)) > 0 && receivablesMoney != null){
                BigDecimal dayRoi = receivablesMoney.divide(putinMoney, 2, RoundingMode.HALF_UP);
                dayRoiList.add(dayRoi);
                roiTable.put("dayRoi",dayRoi);
            }else{
                dayRoiList.add(new BigDecimal("0.00"));
                roiTable.put("dayRoi",new BigDecimal("0.00"));
            }

            // 预期ROI
            BigDecimal expectReceivablesMoney = expectReceivablesStatis.get(currentDateToStr + " 00:00:00");
            if(putinMoney.compareTo(new BigDecimal(0)) > 0 && expectReceivablesMoney != null){
                BigDecimal expectDayRoi = expectReceivablesMoney.divide(putinMoney, 2, RoundingMode.HALF_UP);
                expectDayRoiList.add(expectDayRoi);
                roiTable.put("expectDayRoi",expectDayRoi);
            }else{
                expectDayRoiList.add(new BigDecimal("0.00"));
                roiTable.put("expectDayRoi",new BigDecimal("0.00"));
            }
            roiTableList.add(roiTable);

            currentDate = currentDate.plusDays(1);  // 将日期增加1天
        }

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("dayList", dayList);
        resultMap.put("dayRoiList", dayRoiList);
        resultMap.put("expectDayRoiList", expectDayRoiList);
        resultMap.put("roiTableList", roiTableList);

        return resultMap;

    }

    /**
     * 客单价月度统计
     * @param crmRoiPutinPageBO
     * @return
     */
    @Override
    public Map<String, Object> priceStatisForMonth(CrmRoiPutinPageBO crmRoiPutinPageBO){
        // 客单价(总消耗/总表单量)
        String month = crmRoiPutinPageBO.getMonth();
        if(StringUtils.isBlank(month)){
            LocalDate today = LocalDate.now();
            LocalDate monthAgo = today.minusMonths(1);
            month = DateUtils.parseDateToStr(DateUtils.YYYY_MM,DateUtils.toDate(monthAgo));
            crmRoiPutinPageBO.setMonth(month);
        }

        String[] split = month.split("-");
        LocalDate startDate = LocalDate.of(Integer.parseInt(split[0]), Integer.parseInt(split[1]), 1);
        LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());


        List<Integer> allDeptIds = new ArrayList<>();

        List<AdminDept> manageDeptList = SpringUtils.getBean(IAdminUserManageDeptService.class).queryManageDeptListByUserId(UserUtil.getUserId());
        List<Integer> manageDeptIdList = manageDeptList.stream().map(AdminDept::getDeptId).collect(Collectors.toList());
        for(Integer deptId : manageDeptIdList){
            allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(deptId));
            allDeptIds.add(deptId);
        }

        allDeptIds.add(UserUtil.getUser().getDeptId());
        allDeptIds.addAll(SpringUtils.getBean(IAdminDeptService.class).queryChildDept(UserUtil.getUser().getDeptId()));
        allDeptIds = allDeptIds.stream().distinct().collect(Collectors.toList());

        if(!CollectionUtils.isEmpty(crmRoiPutinPageBO.getDeptIds())){
            allDeptIds.retainAll(crmRoiPutinPageBO.getDeptIds());
        }else{
            crmRoiPutinPageBO.setDeptIdList(allDeptIds);
        }

        crmRoiPutinPageBO.setDeptIds(allDeptIds);

        List<Long> userList = new ArrayList<>();
        userList.addAll(SpringUtils.getBean(AdminService.class).queryUserIdsByRoleIds());
        //管理部门 数据权限
        List<Long> ManageDeptUserIdList = SpringUtils.getBean(AdminService.class).queryUserIdsByManageDept();
        userList.addAll(ManageDeptUserIdList);
        userList = userList.stream().distinct().collect(Collectors.toList());

        // 总消耗
        List<CrmRoiStatisVO> putinStatisByFormDate = crmRoiPutinService.queryPutinStatisByFormDate(crmRoiPutinPageBO);
        Map<String, BigDecimal> putinStatis = putinStatisByFormDate.stream().collect(Collectors.toMap(CrmRoiStatisVO::getPutinFormDate, CrmRoiStatisVO::getPutinMoney));

        //总表单量
        List<CrmLeadsRoiStatisVO> crmLeadsRoiStatisVOS = crmLeadsService.queryLeadsStatisForData(crmRoiPutinPageBO.getPutinPlatform(), String.valueOf(startDate), String.valueOf(endDate),userList);
        Map<String, Integer> crmLeadsRoiStatis = crmLeadsRoiStatisVOS.stream().collect(Collectors.toMap(CrmLeadsRoiStatisVO::getLeadsCreateTime, CrmLeadsRoiStatisVO::getLeadsCount));

        List<String> dayList = new ArrayList<>();
        List<BigDecimal> priceList = new ArrayList<>();
        List<Map<String,Object>> priceTableList = new ArrayList<>();

        LocalDate currentDate = startDate;
        while (!currentDate.isAfter(endDate)) {
            String currentDateToStr = String.valueOf(currentDate);
            String day = DateFormatUtils.format(DateUtils.toDate(currentDate), "MM-dd");
            dayList.add(day);

            Map<String, Object> priceTable = new HashMap<>();
            priceTable.put("day",day);

            BigDecimal putinMoney = putinStatis.get(currentDateToStr);
            if(putinMoney == null){
                priceList.add(new BigDecimal(0.00));

                priceTable.put("price",new BigDecimal("0.00"));
                priceTableList.add(priceTable);

                currentDate = currentDate.plusDays(1);  // 将日期增加1天
                continue;
            }
            Integer leadsCount = crmLeadsRoiStatis.get(currentDateToStr + " 00:00:00");
            if(leadsCount == null || leadsCount == 0){
                priceList.add(new BigDecimal(0.00));

                priceTable.put("price",new BigDecimal("0.00"));
                priceTableList.add(priceTable);

                currentDate = currentDate.plusDays(1);  // 将日期增加1天
                continue;
            }

            BigDecimal dayRoi = putinMoney.divide(new BigDecimal(leadsCount), 2, RoundingMode.HALF_UP);
            priceList.add(dayRoi);

            priceTable.put("price",dayRoi);
            priceTableList.add(priceTable);

            currentDate = currentDate.plusDays(1);  // 将日期增加1天
        }

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("dayList", dayList);
        resultMap.put("priceList", priceList);
        resultMap.put("priceTableList", priceTableList);

        return resultMap;
    }

    /**
     * 预计收益统计
     * @param crmRoiPutinPageBO
     * @return
     */
    public Map<String, Object> projectedRevenueStatis(CrmRoiPutinPageBO crmRoiPutinPageBO){

        String year = crmRoiPutinPageBO.getYear();
        if(StringUtils.isBlank(year)){
            year = DateUtils.dateTimeNow(DateUtils.YYYY);
        }

        // 获取选择部门及下属部门的所有用户
        List<Long> userList = new ArrayList<>();
        if(crmRoiPutinPageBO.getDeptIds() != null){
            long[] longs = crmRoiPutinPageBO.getDeptIds().stream().mapToLong(t -> t.longValue()).toArray();
            userList.addAll(adminService.queryUserListByDeptIds(longs));
        }else{
            if(crmRoiPutinPageBO.getIsAuth() == 1){
                userList.addAll(SpringUtils.getBean(AdminService.class).queryUserIdsByRoleIds());
                //管理部门 数据权限
                List<Long> ManageDeptUserIdList = SpringUtils.getBean(AdminService.class).queryUserIdsByManageDept();
                userList.addAll(ManageDeptUserIdList);
                userList = userList.stream().distinct().collect(Collectors.toList());
            }else{
                List<AdminUserVO> adminUserBOList = adminUserService.queryUserList(null).getList();
                userList.addAll(adminUserBOList.stream().map(AdminUserVO::getUserId).collect(Collectors.toList()));
                userList = userList.stream().distinct().collect(Collectors.toList());
            }
        }

        List<JSONObject> hasOverdue = baseMapper.projectedRevenueStatis(year,userList, 1);
        Map<String, BigDecimal> hasOverdueMap = new HashMap<>();
        hasOverdue.forEach(item -> {
            hasOverdueMap.put(item.getString("repaymentDueDate"), item.getBigDecimal("money"));
        });

        List<JSONObject> noOverdue = baseMapper.projectedRevenueStatis(year,userList, 0);
        Map<String, BigDecimal> noOverdueMap = new HashMap<>();
        noOverdue.forEach(item -> {
            noOverdueMap.put(item.getString("repaymentDueDate"), item.getBigDecimal("money"));
        });

        List<String> monthList = new ArrayList<>();
        List<BigDecimal> hasOverdueList = new ArrayList<>();
        List<BigDecimal> noOverdueList = new ArrayList<>();

        for(int i = 1; i <= 12; i++){
            String month = "";
            String monthData = "";
            if(i < 10){
                month = year + "0" + i;
                monthData = year + "-" + "0" + i;
            }else{
                month = year + i;
                monthData = year + "-" + i;
            }
            monthList.add(monthData);
            BigDecimal money = hasOverdueMap.get(month);
            if(money == null){
                hasOverdueList.add(new BigDecimal(0));
            }else{
                hasOverdueList.add(money);
            }

            BigDecimal money1 = noOverdueMap.get(month);
            if(money1 == null){
                noOverdueList.add(new BigDecimal(0));
            }else{
                noOverdueList.add(money1);
            }
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("monthList", monthList);
        resultMap.put("hasOverdueList", hasOverdueList);
        resultMap.put("noOverdueList", noOverdueList);

        return resultMap;
    }
}
